/* e100_init.c - e100_init */

#include <xinu.h>

uint16 e100_eeprom_read(uint16 iobase, uint8 addr);

/*------------------------------------------------------------------------
 * e100_init - initialize Intel Hub 10D/82567LM Ethernet NIC
 *------------------------------------------------------------------------
 */

void 	e100_init(
	struct 	ether *ethptr
	)
{
	uint16  command;
	uint16	rar;
	uint16	pci_status;

	/* Read PCI configuration information */
	/* Read I/O base address */

	pci_bios_read_config_dword(ethptr->pcidev, E100_PCI_IOBASE,
			(uint32 *)&ethptr->iobase);
	ethptr->iobase &= ~1;
	ethptr->iobase &= 0xffff; /* the low bit is set to indicate I/O */
	kprintf("e100: i/o base: %x\n", ethptr->iobase);

	/* Read flash base address */

	pci_bios_read_config_dword(ethptr->pcidev, E100_PCI_FLASHBASE,
			(uint32 *)&ethptr->flashbase);

	/* Read memory base address */

	pci_bios_read_config_dword(ethptr->pcidev, E100_PCI_MEMBASE,
			(uint32 *)&ethptr->membase);
	ethptr->membase &= ~2; 	/* if mem address is below 1 MB */

	/* Read interrupt line number */

	pci_bios_read_config_byte (ethptr->pcidev, E100_PCI_IRQ,
			(byte *)&(ethptr->dev->dvirq));
	kprintf("e100: IRQ: %d\n", ethptr->dev->dvirq);

	/* Enable PCI bus master, memory access and I/O access */

	pci_bios_read_config_word(ethptr->pcidev, E100_PCI_COMMAND, 
			&command);
	command |= E100_PCI_CMD_MASK;
	pci_bios_write_config_word(ethptr->pcidev, E100_PCI_COMMAND, 
			command);
	
	/*	Get PCI device status	*/
	pci_bios_read_config_word(ethptr->pcidev, E100_PCI_STATUS,
			&pci_status);
	kprintf("PCI status is %x\n", pci_status);
	
	/*---------------------------------------------------------
	 * e100_reset - bring the hardware into a known good state
	 *---------------------------------------------------------
	 */

	outl(ethptr->iobase + 0x08, 0x0002);
	e100_write_flush(ethptr->iobase);
	DELAY(20);
	outl(ethptr->iobase + 0x08, 0x0000);
	e100_write_flush(ethptr->iobase);
	DELAY(20);
	e100_disable_irq(ethptr);

	/* Read the MAC address */
	
	rar = e100_eeprom_read(ethptr->iobase, 0x00);
	ethptr->devAddress[0] = rar & 0xff;
	ethptr->devAddress[1] = rar >> 8;
	rar = e100_eeprom_read(ethptr->iobase, 0x01);
	ethptr->devAddress[2] = rar & 0xff;
	ethptr->devAddress[3] = rar >> 8;
	rar = e100_eeprom_read(ethptr->iobase, 0x02);
	ethptr->devAddress[4] = rar & 0xff;
	ethptr->devAddress[5] = rar >> 8;
	kprintf("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n",
			0xff&ethptr->devAddress[0],
			0xff&ethptr->devAddress[1],
			0xff&ethptr->devAddress[2],
			0xff&ethptr->devAddress[3],
			0xff&ethptr->devAddress[4],
			0xff&ethptr->devAddress[5]);
			
	ethptr->cuc_cmd = cuc_start;
}

uint16 e100_eeprom_read(uint16 iobase, uint8 addr)
{
	uint32 cmd_addr_data = 0;
	uint16 data = 0;
	uint8 ctrl;
	int i;
	
	cmd_addr_data = ((op_read << 6) | addr) << 16;
	/* Activate the EEPROM */
	outb(iobase + E100_EEPROM_LO, eecs | eesk);
	/* Write 1 to EESK bit then wait for the minimum SK high time	*/
	e100_write_flush(iobase);
	DELAY(4);

	/* Bit-bang to read word from eeprom */
	for (i = 31; i >= 0; i--) {
		ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
		/* Write 0 to EESK bit then wait for the minimum SK low time	*/
		/* Write the opcode or address field to the EEDI bit	*/
		outb(iobase + E100_EEPROM_LO, ctrl);
		e100_write_flush(iobase);
		DELAY(4);
		
		/* Write 1 to EESK bit then wait for the minimum SK high time	*/
		outb(iobase + E100_EEPROM_LO, ctrl | eesk);
		e100_write_flush(iobase);
		DELAY(4);
		
		ctrl = inb(iobase + E100_EEPROM_LO);
		
		/*	Read a bit from the EEDO bit	*/
		if ( i < 16 ) {
			data = (data << 1) | (ctrl & eedo ? 1 : 0);
		}
	}

	/* Deactivate the EEPROM */
	outb(iobase + E100_EEPROM_LO, 0);
	e100_write_flush(iobase);
	DELAY(4);

	return data;
}
